export function patch(oldVnode, vnode) {
    if (!oldVnode) {
        return createEl(vnode)
    }

    if (oldVnode.nodeType === 1) {
        // 创建新DOM
        let el = createEl(vnode)
        // 替换DOM 1.获取父节点 2.插入 3.删除
        let parentEl = oldVnode.parentNode
        parentEl.insertBefore(el, oldVnode.nextsibling)
        parentEl.removeChild(oldVnode)
        return el
    } else {
        // 标签相同
        if (oldVnode.tag !== vnode.tag) {
            return oldVnode.el.parentNode.replaceChild(createEl(vnode), oldVnode.el)
        }
        // 标签相同 text节点不同 tag为undefined ===> <p>1</p> <p>2</p>
        if (!oldVnode.tag) {
            if (oldVnode.text !== vnode.text) {
                oldVnode.el.textContent = vnode.text
            }
        }

        // 标签相同 text节点相同 属性不同
        const el = vnode.el = oldVnode.el
        updataRpors(vnode, oldVnode.data)

        const oldChildren = oldVnode.children || []
        const newChildren = vnode.children || []
        if (oldChildren.length > 0 && newChildren.length > 0) {// 老的新的都有子节点
            updateChild(oldChildren, newChildren, el)
        } else if (newChildren.length > 0) { // 新的有 旧的没有
            for (let i = 0; i < newChildren.length; i++) {
                const child = newChildren[i]
                // 添加进DOM节点
                el.appendChild(createEl(child))
            }
        } else if (oldChildren.length > 0) {// 新的没有 旧的没有
            el.innerHTML = ''
        }
    }
}

function updateChild(oldChildren, newChildren, parent) {
    let oldStartIndex = 0
    let oldStartVnode = oldChildren[oldStartIndex]
    let oldEndIndex = oldChildren.length - 1
    let oldEndVnode = oldChildren[oldEndIndex]

    let newStartIndex = 0
    let newStartVnode = newChildren[newStartIndex]
    let newEndIndex = newChildren.length - 1
    let newEndVnode = newChildren[newEndIndex]

    function isSomeVnode(oldContext, newContext) {
        return (oldContext.tag === newContext.tag) && (oldContext.key === newContext.key)
    }

    function makeIndexBykey(child) {
        let map = {}
        child.forEach((item, index) => {
            if (item.key) {
                map[item.key] = index
            }
        })
        return map
    }
    // 创建映射表
    const map = makeIndexBykey(oldChildren)

    while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) {
        // 节点相同
        if (isSomeVnode(oldStartVnode, newStartVnode)) {
            patch(oldStartVnode, newStartVnode)
            oldStartVnode = oldChildren[++oldStartIndex]
            newStartVnode = newChildren[++newStartIndex]
        } else if (isSomeVnode(oldEndVnode, newEndVnode)) {
            patch(oldEndVnode, newEndVnode)
            oldEndVnode = oldChildren[--oldEndIndex]
            newEndVnode = newChildren[--newEndIndex]
        } else if (isSomeVnode(oldStartVnode, newEndVnode)) {// 旧前新后
            patch(oldStartVnode, newEndVnode)
            oldStartVnode = oldChildren[++oldStartIndex]
            newEndVnode = newChildren[--newEndIndex]
        } else if (isSomeVnode(oldEndVnode, newStartVnode)) {// 旧后新前
            patch(oldEndVnode, newStartVnode)
            oldEndVnode = oldChildren[--oldEndIndex]
            newStartVnode = newChildren[++newStartIndex]
        } else {
            const moveIndex = map[newStartVnode.key]
            if (moveIndex == undefined) {
                parent.insertBefore(createEl(newStartVnode), oldStartVnode.el)
            } else {
                const moveVnode = oldChildren[moveIndex]
                oldChildren[moveIndex] = null
                parent.insertBefore(moveVnode.el, oldStartVnode.el)
                // 处理子节点
                patch(moveVnode, newStartVnode)
            }

            // 指针移动
            newStartVnode = newChildren[++newStartIndex]
        }
    }

    if (newStartIndex <= newEndIndex) {
        for (let i = newStartIndex; i <= newEndIndex; i++) {
            parent.appendChild(createEl(newChildren[i]))
        }
    }
}

// 处理属性
function updataRpors(vnode, oldProps = {}) {
    const newProps = vnode.data || {}
    const el = vnode.el

    // 老的有，新没有
    for (const key in oldProps) {
        if (!newProps[key]) {
            el.removeAttribute(key)
        }
    }

    // 老的新的不一样
    const oldStyle = oldProps.style || {}
    const newStyle = newProps.style || {}
    for (const key in oldStyle) {
        if (!newStyle[key]) {
            el.style[key] = ''
        }
    }

    for (const key in newProps) {
        if (key === 'style') {
            for (const styleName in newProps.style) {
                el.style[styleName] = newProps.style[styleName]
            }
        } else if (key === 'class') {
            el.className = newProps.class
        } else {
            el.setAttribute(key, newProps[key])
        }
    }

}

function createEl(vnode) {
    let { tag, children, key, data, text } = vnode
    if (typeof tag === 'string') {
        if (createComponent(vnode)) {
            return vnode.componentInstance.$el
        } else {
            vnode.el = document.createElement(tag)
            updataRpors(vnode)
            if (children.length > 0) {
                children.forEach(child => {
                    vnode.el.appendChild(createEl(child))
                });
            }
        }
    } else {
        vnode.el = document.createTextNode(text)
    }
    return vnode.el
}

// 创建虚拟DOM
function createComponent(vnode) {
    let i = vnode.data
    if ((i = i.hook) && (i = i.init)) {
        i(vnode)
    }
    if (vnode.componentInstance) {
        return true
    }
    return false
}